﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using pklib.Model;
using MonitoredUndo;

namespace pklib.ViewModel {
	public class ObservableCollectionVM<ModelT, ViewModelT> : ObservableCollection<ViewModelT> where ViewModelT : ViewModelBase<ModelT>, new() where ModelT : ModelBase, new() {

		private ObservableCollection<ModelT> Source;

		public ObservableCollectionVM(ObservableCollection<ModelT> Source) {
			this.Source = Source;
			this.Source.CollectionChanged += this.OnSourceCollectionChanged;
			foreach (ModelT st in this.Source)
				this.Add(new ViewModelT().SetTarget(st) as ViewModelT);
		}

		private bool CascadeChanges = true;

		protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e) {
			if (this.CascadeChanges) {
				CascadeChanges = false;
				if (e.Action == NotifyCollectionChangedAction.Reset) {
					this.Source.Clear();

					foreach (ViewModelT st in this)
						this.Source.Add(st.Target as ModelT);
				} else {
					if (null != e.OldItems) {
						foreach (ViewModelT oi in e.OldItems)
							this.Source.Remove(oi.Target as ModelT);
					}
					if (null != e.NewItems) {
						var InsertIndex = e.NewStartingIndex;
						foreach (ViewModelT ni in e.NewItems)
							this.Source.Insert(InsertIndex++, ni.Target as ModelT);
					}
				}
				CascadeChanges = true;
			}
			base.OnCollectionChanged(e);
		}

		void OnSourceCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) {
			if (this.CascadeChanges) {

				CascadeChanges = false;
				if (e.Action == NotifyCollectionChangedAction.Reset) {
					this.Clear();

					foreach (ModelT st in this.Source)
						this.Add(new ViewModelT().SetTarget(st) as ViewModelT);
				} else {
					if (null != e.OldItems) {
						foreach (ModelT oi in e.OldItems)
							this.Remove(this.First(tt => tt.Target == oi));
					}
					if (null != e.NewItems) {
						var InsertIndex = e.NewStartingIndex;
						foreach (ModelT ni in e.NewItems)
							this.Insert(InsertIndex++, new ViewModelT().SetTarget(ni) as ViewModelT);
					}
				}
				CascadeChanges = true;
			}
		}
	}
}
